# ADX规则
import talib
from PyQt5 import QtCore
# CTP行情库
from vnctpmd import *
import numpy as np
import globalvar
import numba as nb

class MyFilter():
    def __init__(self, periodint):
        self.periodint = periodint
        self.high = []
        self.low = []
        self.close = []

    # 由于实盘是Tick驱动，所以实盘直接调用OnFilterByTick，分2种情况：
    # （1）OnFilter(self, mddata, type)方法，参数type=True 时，调用OnFilterByBar获得返回值True或False，适合非TICK级回测
    # （2）OnFilter(self, mddata, type)方法，参数type=False 时，基于Tick级过滤规则，适合基于Tick回调的实盘
    # 返回值：True(设“且”时，不过滤交易信号)，False(设“且”时，过滤交易信号)
    # 调用OnFilter的有2处：
    # （1）回测模块 module_backtest.py 文件中 ，由 CalFilter(self, flist, kline, id)方法实现触发OnFilter(self,mddata,True)
    # （2）策略管理模块module_strategy.py文件中，由CalFilter(self, flist, kline, id)方法实现触发OnFilter(self,mddata,False)
    def OnFilter(self, mddata, type):
        if type:
            # 非Tick级(一般是M1周期及以上K线量化回测)
            # OnFilter(self, mddata, type)的参数mddata数据结构和OnFilterByBar(self, mddata)的mddata参数类型一致
            # 量化回测module_backtest.py的CalFilter，可直接触发OnFilterByBar
            return self.OnFilterByBar(mddata)
        else:
            # Tick级，分2种情况（1）直接撰写TICK级规则代码 （2）为减少计算，每K线周期只计算一次OnFilterByBar(self, mddata)
            return self.OnFilterByTick(globalvar.md.GetKline(mddata.InstrumentID, 0))
            # mddata =  globalvar.md.GetKline(mddata.InstrumentID, 0)[0].Close)

    def OnFilterByTick(self, tickdata):
        # Tick级，选（2）为减少计算，每K线周期只计算一次OnFilterByBar(self, tickdata),当然你想每次Tick都计算也可以屏蔽下方部分代码
        # tickdata =  globalvar.md.GetKline(tickdata.InstrumentID, 0)[0].Close)
        if globalvar.md.GetKline(tickdata.InstrumentID, 0)[0].KlineTime != self.lastKlineTime:
            # 根据DLL生成的K线分时数据判断，只有当分钟数变化时，才计算一次，并将结果保存，无需每次Tick回调时都计算过滤规则
            # 对周期分钟数求余若为0，则该周期结束，更新规则计算结果
            if self.lastKlineTime%self.periodint == 0:
                self.lastKlineTime=globalvar.md.GetKline(tickdata.InstrumentID, 0)[0].KlineTime
                self.result = self.OnFilterByBar(tickdata)
        return self.result


    # 量化回测默认是基于M1及以上级别
    # 对于回测数据是M1以上级别数据，即非Tick级规则，直接调用OnFilterByBar方法即可
    def OnFilterByBar(self, kdata):
        # if kdata=="":
        # kdata =  globalvar.md.GetKline(kdata.InstrumentID, 0)[0].Close)

        # klinetime = klinedata.klinetime.decode()
        self.InstrumentID = kdata.InstrumentID.decode()
        self.high.append(float(kdata.high))
        self.low.append(float(kdata.low))
        self.close.append(float(kdata.close))
        try:
            float_high = [float(x) for x in self.high]
            float_low = [float(x) for x in self.low]
            float_close = [float(x) for x in self.close]
        except Exception as e:
            print('OnFilter error:%s [%d]' % (e, id))
        adx = talib.ADX(np.array(float_high), np.array(float_low), np.array(float_close), 14)
        thisadx = adx[len(adx) - 1]
        # ADX帮助交易员确认趋势强度，一般在其大于25时进行趋势交易策略，低于25则避免趋势交易策略。
        # ADX描述的是趋势的强弱，而非趋势。使用者容易将ADX下降误以为趋势反转，其实只是趋势强度降低，但是趋势尚在。

        if thisadx > 25:
            return True
        else:
            return False
